package com.niiwoo.civet.trade.listener;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcContext;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.google.common.collect.Lists;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.trade.constant.RabbitConstant;
import com.niiwoo.civet.trade.dao.entity.ProjectContract;
import com.niiwoo.civet.trade.dao.entity.ProjectInvestOrder;
import com.niiwoo.civet.trade.dao.entity.UserInvestConfig;
import com.niiwoo.civet.trade.dao.mapper.ProjectInvestOrderMapperExt;
import com.niiwoo.civet.trade.dto.BatchInvestFinishedMsg;
import com.niiwoo.civet.trade.dto.common.PeriodDTO;
import com.niiwoo.civet.trade.dto.common.SysInvestConfigDTO;
import com.niiwoo.civet.trade.dto.request.SysInvestConfigChangeDTO;
import com.niiwoo.civet.trade.enums.InvestWayEnum;
import com.niiwoo.civet.trade.enums.PeriodUnitEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.service.dubbo.invest.AutoInvestDubboServiceImpl;
import com.niiwoo.civet.trade.service.local.invest.AutoBatchInvestService;
import com.niiwoo.civet.trade.service.local.invest.InvestService;
import com.niiwoo.civet.user.dto.request.AppButtonDTO;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.enums.MessageTemplateKeyEnum;
import com.niiwoo.civet.user.enums.UserLetterTypeEnum;
import com.niiwoo.civet.user.service.UserLetterDubboService;
import com.niiwoo.tripod.base.plan.RepaymentPlanContext;
import com.niiwoo.tripod.base.plan.support.RepaymentPlanDTO;
import com.niiwoo.tripod.base.plan.support.RepaymentTypeEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

/**
 * Created by zhangwanli on 2017/12/15.
 */
@Slf4j
@Component
public class InvestmentListener {

    private static final String SUCCEED_ENABLE_AUTO = "本次批量投资%d个借款标，投资总额%s元，预期收益%s元，账户余额%s元。您已开启自动投资，有符合您要求的借款标上线将为您自动投资。";
    private static final String SUCCEED_DISABLE_AUTO = "本次批量投资%d个借款标，投资总额%s元，预期收益%s元，账户余额%s元。建议您开启自动投资，开启后有符合您要求的借款标上线将为您自动投资。";
    private static final String FAILED_ENABLE_AUTO = "当前无符合您批量投资要求的借款标。您已开启自动投资，有符合您要求的借款标上线将为您自动投资。";
    private static final String FAILED_DISABLE_AUTO = "当前无符合您批量投资要求的借款标。建议您开启自动投资，开启后有符合您要求的借款标上线将为您自动投资。";

    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    private UserLetterDubboService userLetterDubboService;
    @Autowired
    private AutoBatchInvestService autoBatchInvestService;
    @Autowired
    private InvestService investService;
    @Autowired
    private AutoInvestDubboServiceImpl autoInvestDubboService;
    @Autowired
    private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;

    @RabbitListener(queues = RabbitConstant.Queue.BATCH_INVEST_FINISHED)
    public void onBatchInvestFinished(BatchInvestFinishedMsg msg, Message message, Channel channel) throws IOException {
        log.info("收到批量投资成功消息,msg={}", msg);
        try {
            handleBatchInvestFinishedMsg(msg);
        } catch (Exception e) {
            log.error("处理批量投资成功MQ消息出错", e);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    @RabbitListener(queues = RabbitConstant.Queue.SIGN_COMMISSION_AUTH_AGREEMENT)
    public void onSignCommissionAuthAgreementMsg(Long contractId, Message message, Channel channel) throws IOException {
        log.info("收到签署委托授权协议合同消息,contractId={}", contractId);
        try {
            investService.signCommissionAuthAgreement(contractId);
        } catch (Exception e) {
            log.error("处理签署委托授权协议合同消息出错", e);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    @RabbitListener(queues = RabbitConstant.Queue.SIGN_RISK_TIPS_AGREEMENT)
    public void onSignRiskTipsAgreementMsg(Long investOrderId, Message message, Channel channel) throws IOException {
        log.info("收到签署投资风险提示书合同消息,investOrderId={}", investOrderId);
        try {
            if (!HintManagerHolder.isMasterRouteOnly()) {
                HintManager hintManager = HintManager.getInstance();
                hintManager.setMasterRouteOnly();
            }
            ProjectInvestOrder order = projectInvestOrderMapperExt.selectByPrimaryKey(investOrderId);
            if(order.getCreditorSaleDetailId() != null){
                investService.transferSignRiskTipsAgreement(order);
            } else {
                ProjectContract contract = investService.initRiskTipsAgreement(investOrderId);
                investService.signRiskTipsAgreement(contract);
            }

        } catch (Exception e) {
            log.error("处理签署投资风险提示书合同消息出错", e);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    @RabbitListener(queues = RabbitConstant.Queue.SYS_INVEST_CONFIG_CHANGE)
    public void onSysInvestConfigChangedMsg(SysInvestConfigChangeDTO change, Message message, Channel channel) throws IOException {
    	//5.4.0 新增配置是 时候不需要逻辑
        log.info("收到系统投资配置变更消息,id={},op={}", change.getId(), change.getOp().name());
//        try {
//            Optional<SysInvestConfigDTO> optional = autoBatchInvestService.querySysInvestConfigList().stream()
//                    .filter(input -> input.getId().equals(change.getId()))
//                    .findFirst()
//                    .map(input -> {
//                        SysInvestConfigDTO dto = new SysInvestConfigDTO();
//                        dto.setId(input.getId());
//
//                        return dto;
//                    });
//            if (optional.isPresent()) {
//                SysInvestConfigDTO dto = optional.get();
//                switch (change.getOp()) {
//                    case ADD:
//                        autoInvestDubboService.onSysInvestSettingAdded(dto);
//                        break;
//                    case DELETE:
//                        break;
//                    case MODIFY:
//                        break;
//                    default:
//                        break;
//                }
//            }
//        } catch (Exception e) {
//            log.error("处理系统投资配置变更消息出错", e);
//        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    private void handleBatchInvestFinishedMsg(BatchInvestFinishedMsg msg) {
        String userId = msg.getUserId();
        BigDecimal totalInvestAmount = BigDecimal.ZERO;
        BigDecimal totalExpectIncome = BigDecimal.ZERO;
        int succeedCount;
        List<BatchInvestFinishedMsg.Entry> entryList = msg.getEntryList();
        if (entryList == null || entryList.isEmpty()) {
            succeedCount = 0;
        } else {
            succeedCount = entryList.size();
            for (BatchInvestFinishedMsg.Entry entry : entryList) {
                RepaymentTypeEnum repaymentType = RepaymentTypeEnum.enumOf(entry.getRepaymentType());
                BigDecimal investAmount = entry.getInvestAmount();
                BigDecimal yearRate = entry.getYearRate();
                Integer deadline = entry.getDeadline();
                Byte projectType = entry.getProjectType();
                com.niiwoo.tripod.base.plan.support.PeriodUnitEnum periodUnit = com.niiwoo.tripod.base.plan.support.PeriodUnitEnum.enumOf(entry.getDeadlineUnit());
                List<RepaymentPlanDTO> planList = RepaymentPlanContext.getRepaymentPlan(repaymentType, projectType, investAmount, yearRate, deadline, periodUnit, msg.getInvestTime());
                for (RepaymentPlanDTO plan : planList) {
                    totalExpectIncome = totalExpectIncome.add(plan.getInterest());
                }
                totalInvestAmount = totalInvestAmount.add(investAmount);
            }
        }
        //批量投资完成发送通知
        String content;
        UserInvestConfig autoConfig = autoBatchInvestService.queryUserInvestConfigForMaster(userId, InvestWayEnum.AUTO);
        boolean enableAuto = autoConfig != null && autoConfig.getEnableAuto() == 1;
        UserLetterRequestDTO req = new UserLetterRequestDTO();
        req.setToUserId(userId);
        req.setUserLetterTypeEnum(UserLetterTypeEnum.ONLY_LETTER);
        if (succeedCount > 0) {
            AccountBaseResponse accountInfo = accountDubboService.loadNiiwooAccount(userId, UserRoleEnum.INVESTOR);
            //由于主从延迟将会导致余额异常，余额查询主库
            accountInfo =  accountDubboService.loadAccountByIdFromMaster(accountInfo.getAccountId());
            BigDecimal availableAmount = accountInfo.getAvailableAmount();
            if (enableAuto) {
                content = String.format(SUCCEED_ENABLE_AUTO, succeedCount, totalInvestAmount, totalExpectIncome, availableAmount);
                req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.BATCH_INVEST_SUCCEED_ENABLE_AUTO);
                req.setLetterTemplateParamList(Lists.newArrayList(succeedCount, totalInvestAmount, totalExpectIncome, availableAmount));
            } else {
                content = String.format(SUCCEED_DISABLE_AUTO, succeedCount, totalInvestAmount, totalExpectIncome, availableAmount);
                req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.BATCH_INVEST_SUCCEED_DISABLE_AUTO);
                req.setLetterTemplateParamList(Lists.newArrayList(succeedCount, totalInvestAmount, totalExpectIncome, availableAmount));
                AppButtonDTO button = new AppButtonDTO();
                button.setButtonType(AppButtonDTO.ButtonTypeEnum.AUTO_INVEST);
                button.setLabel("开启自动投资");
                req.setLetterButtonList(Lists.newArrayList(button));
            }
        } else {
            if (enableAuto) {
                content = FAILED_ENABLE_AUTO;
                req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.BATCH_INVEST_FAILED_ENABLE_AUTO);
            } else {
                content = FAILED_DISABLE_AUTO;
                req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.BATCH_INVEST_FAILED_DISABLE_AUTO);
                AppButtonDTO button = new AppButtonDTO();
                button.setButtonType(AppButtonDTO.ButtonTypeEnum.AUTO_INVEST);
                button.setLabel("开启自动投资");
                req.setLetterButtonList(Lists.newArrayList(button));
            }
        }
        log.info("发送批量投资结果消息:userId={},msg={}", userId, content);
        RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(req));
    }

}
